{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sine model Analysis/Synthesis - MusicBricks Tutorial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial will guide you through some tools for performing spectral analysis and synthesis using the Essentia library (http://www.essentia.upf.edu). \n",
    "\n",
    "This algorithm shows how to analyze the input signal, and resynthesize it again, allowing to apply new transformations directly on the spectral domain."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should first install the Essentia library with Python bindings. Installation instructions are detailed here: http://essentia.upf.edu/documentation/installing.html . \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Processing steps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import essentia in streaming mode\n",
    "import essentia\n",
    "import essentia.streaming as es"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define the parameters of the STFT workflow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# algorithm parameters\n",
    "params = { 'frameSize': 2048, 'hopSize': 512, 'startFromZero': False, 'sampleRate': 44100, \\\n",
    "          'maxnSines': 100,'magnitudeThreshold': -74,'minSineDur': 0.02,'freqDevOffset': 10, \\\n",
    "          'freqDevSlope': 0.001}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Specify input and output audio filenames"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "inputFilename = 'singing-female.wav'\n",
    "outputFilename = 'singing-female-sindemodel.wav'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create an audio loader and import audio file\n",
    "loader = es.MonoLoader(filename = inputFilename, sampleRate = 44100)\n",
    "pool = essentia.Pool()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define algorithm chain for frame-by-frame process: \n",
    "FrameCutter -> Windowing -> FFT -> IFFT -> OverlapAdd -> AudioWriter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# algorithm instantation\n",
    "fcut = es.FrameCutter(frameSize=params['frameSize'], hopSize=params['hopSize'], startFromZero=False)\n",
    "w = es.Windowing(type=\"blackmanharris92\")\n",
    "fft = es.FFT(size=params['frameSize'])\n",
    "smanal = es.SineModelAnal(\n",
    "    sampleRate=params['sampleRate'],\n",
    "    maxnSines=params['maxnSines'],\n",
    "    magnitudeThreshold=params['magnitudeThreshold'],\n",
    "    freqDevOffset=params['freqDevOffset'],\n",
    "    freqDevSlope=params['freqDevSlope'],\n",
    "    )\n",
    "smsyn = es.SineModelSynth(\n",
    "    sampleRate=params['sampleRate'],\n",
    "    fftSize=params['frameSize'],\n",
    "    hopSize = params['hopSize']\n",
    "    )\n",
    "ifft = es.IFFT(size=params['frameSize'])\n",
    "overl = es.OverlapAdd (\n",
    "    frameSize=params['frameSize'],\n",
    "    hopSize=params['hopSize'],\n",
    "    gain=1./params['frameSize'],\n",
    "    )\n",
    "awrite = es.MonoWriter (filename=outputFilename, sampleRate=params['sampleRate'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we set the algorithm network and store the processed audio samples in the output file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# analysis\n",
    "loader.audio >> fcut.signal\n",
    "fcut.frame >> w.frame\n",
    "w.frame >> fft.frame\n",
    "fft.fft >> smanal.fft\n",
    "# synthesis\n",
    "smanal.magnitudes >> smsyn.magnitudes\n",
    "smanal.frequencies >> smsyn.frequencies\n",
    "smanal.phases >> smsyn.phases\n",
    "smsyn.fft >> ifft.fft\n",
    "ifft.frame >> overl.frame\n",
    "overl.signal >> awrite.audio\n",
    "overl.signal >> (pool, 'audio')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally we run the process that will store an output file in a WAV file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[wav @ 0x562518d15b60] Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead.\n",
      "[wav @ 0x562518d15b60] Encoder did not produce proper pts, making some up.\n"
     ]
    }
   ],
   "source": [
    "essentia.run(loader)"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "2146b6db258b20f3c29b7f1d7771ef33b30f307033b5e0e893928c1a552d47a9"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
